#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <time.h>
#include <dirent.h>

#include "cJSON.h"
#include "common.h"
#include "user.h"

// 日志函数声明
enum LogLevel { LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_WARNING, LOG_LEVEL_ERROR, LOG_LEVEL_FATAL };
int logInit(const char *filename, enum LogLevel level, int consoleOutput);
void logCleanup();
void logDebug(const char *format, ...);
void logInfo(const char *format, ...);
void logWarning(const char *format, ...);
void logError(const char *format, ...);
void logFatal(const char *format, ...);

// 心跳函数声明
typedef struct HeartbeatConfig HeartbeatConfig;
HeartbeatConfig *heartbeatInit(int interval, int timeout, int (*sendFunc)(void *), void *context);
int heartbeatStart(HeartbeatConfig *config);
void heartbeatStop(HeartbeatConfig *config);
void heartbeatDestroy(HeartbeatConfig *config);

#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8080
#define HEARTBEAT_INTERVAL 10  // 10秒
#define HEARTBEAT_TIMEOUT 30   // 30秒
#define LOCAL_DATA_DIR "./local_data"

// 客户端上下文结构体定义
typedef struct ClientContext {
    int sockfd;
    void *heartbeat;
    int running;
    UserInfo user;
    int loggedIn;
} ClientContext;

// 客户端上下文
typedef struct {
    int sockfd;
    HeartbeatConfig *heartbeat;
    int running;
    UserInfo user;
    int loggedIn;
} ClientContext;

// 接收响应的互斥锁和条件变量
pthread_mutex_t responseMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t responseCond = PTHREAD_COND_INITIALIZER;
char g_responseBuffer[MAX_BUFFER_SIZE];
unsigned char g_responseDataType;
int g_responseReady = 0;

// 发送心跳函数
static int clientSendHeartbeat(void *arg) {
    ClientContext *context = (ClientContext *)arg;
    
    if (context->sockfd <= 0) {
        return -1;
    }
    
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "type", "heartbeat");
    cJSON_AddNumberToObject(root, "timestamp", time(NULL));
    
    char *jsonStr = cJSON_PrintUnformatted(root);
    int ret = sendPacket(context->sockfd, DATA_TYPE_HEARTBEAT, jsonStr);
    
    cJSON_free(jsonStr);
    cJSON_Delete(root);
    
    if (ret < 0) {
        logError("Failed to send heartbeat");
        return -1;
    }
    
    logDebug("Heartbeat sent");
    return 0;
}

// 接收服务器响应
static void *receiveResponse(void *arg) {
    ClientContext *context = (ClientContext *)arg;
    char jsonBuffer[MAX_BUFFER_SIZE];
    unsigned char dataType;
    
    while (context->running) {
        int ret = recvPacket(context->sockfd, jsonBuffer, MAX_BUFFER_SIZE, &dataType);
        if (ret > 0) {
            // 复制响应到全局缓冲区并通知等待的线程
            pthread_mutex_lock(&responseMutex);
            strncpy(g_responseBuffer, jsonBuffer, MAX_BUFFER_SIZE - 1);
            g_responseDataType = dataType;
            g_responseReady = 1;
            pthread_cond_signal(&responseCond);
            pthread_mutex_unlock(&responseMutex);
            
            // 处理特殊响应
            if (dataType != DATA_TYPE_ACK && dataType != DATA_TYPE_ERROR) {
                cJSON *root = cJSON_Parse(jsonBuffer);
                if (root) {
                    // 根据不同的数据类型处理响应
                    switch (dataType) {
                        case DATA_TYPE_USER_LOGIN:
                        case DATA_TYPE_USER_REGISTER:
                        case DATA_TYPE_USER_CHANGE_PASSWORD:
                        case DATA_TYPE_USER_DELETE:
                        case DATA_TYPE_USER_QUERY:
                        case DATA_TYPE_DATA_QUERY:
                        case DATA_TYPE_DATA_DELETE:
                        case DATA_TYPE_DATA_SAMPLE:
                            logInfo("Received response for operation");
                            break;
                        default:
                            logWarning("Received unknown data type: %d", dataType);
                            break;
                    }
                    cJSON_Delete(root);
                } else {
                    logError("Failed to parse response from server");
                }
            }
        } else if (ret == 0 || errno != EAGAIN) {
            logError("Connection to server closed or error occurred");
            context->running = 0;
            break;
        }
        
        usleep(100000);  // 100ms
    }
    
    return NULL;
}

// 等待并获取服务器响应
int waitForResponse(char *buffer, int bufferSize, unsigned char *dataType) {
    pthread_mutex_lock(&responseMutex);
    
    // 等待响应
    while (!g_responseReady) {
        pthread_cond_wait(&responseCond, &responseMutex);
    }
    
    // 复制响应数据
    strncpy(buffer, g_responseBuffer, bufferSize - 1);
    *dataType = g_responseDataType;
    g_responseReady = 0;
    
    pthread_mutex_unlock(&responseMutex);
    return strlen(buffer);
}

// 等待并获取服务器响应
int waitForResponse(char *buffer, int bufferSize, unsigned char *dataType) {
    pthread_mutex_lock(&responseMutex);
    
    // 等待响应
    while (!g_responseReady) {
        pthread_cond_wait(&responseCond, &responseMutex);
    }
    
    // 复制响应数据
    strncpy(buffer, g_responseBuffer, bufferSize - 1);
    *dataType = g_responseDataType;
    g_responseReady = 0;
    
    pthread_mutex_unlock(&responseMutex);
    return strlen(buffer);
}

// 数据查询
int dataQuery(ClientContext *context, const char *batch, const char *startDate, const char *endDate, const char *defectType) {
    cJSON *root = cJSON_CreateObject();
    if (batch && strlen(batch) > 0) {
        cJSON_AddStringToObject(root, "batch", batch);
    }
    if (startDate && strlen(startDate) > 0) {
        cJSON_AddStringToObject(root, "startDate", startDate);
    }
    if (endDate && strlen(endDate) > 0) {
        cJSON_AddStringToObject(root, "endDate", endDate);
    }
    if (defectType && strlen(defectType) > 0) {
        cJSON_AddStringToObject(root, "defectType", defectType);
    }
    cJSON_AddStringToObject(root, "username", context->user.username);
    
    char *jsonStr = cJSON_PrintUnformatted(root);
    int ret = sendPacket(context->sockfd, DATA_TYPE_DATA_QUERY, jsonStr);
    
    cJSON_free(jsonStr);
    cJSON_Delete(root);
    
    if (ret < 0) {
        logError("Failed to send data query request");
        return -1;
    }
    
    // 等待响应
    char responseBuffer[MAX_BUFFER_SIZE];
    unsigned char responseType;
    waitForResponse(responseBuffer, MAX_BUFFER_SIZE, &responseType);
    
    // 打印查询结果
    printf("\n--- Data Query Results ---");
    printf("%s\n", responseBuffer);
    printf("------------------------\n");
    
    return 0;
}

// 数据删除
int dataDelete(ClientContext *context, const char *batch, const char *startDate, const char *endDate) {
    cJSON *root = cJSON_CreateObject();
    if (batch && strlen(batch) > 0) {
        cJSON_AddStringToObject(root, "batch", batch);
    }
    if (startDate && strlen(startDate) > 0) {
        cJSON_AddStringToObject(root, "startDate", startDate);
    }
    if (endDate && strlen(endDate) > 0) {
        cJSON_AddStringToObject(root, "endDate", endDate);
    }
    cJSON_AddStringToObject(root, "username", context->user.username);
    
    char *jsonStr = cJSON_PrintUnformatted(root);
    int ret = sendPacket(context->sockfd, DATA_TYPE_DATA_DELETE, jsonStr);
    
    cJSON_free(jsonStr);
    cJSON_Delete(root);
    
    if (ret < 0) {
        logError("Failed to send data delete request");
        return -1;
    }
    
    // 等待响应
    char responseBuffer[MAX_BUFFER_SIZE];
    unsigned char responseType;
    waitForResponse(responseBuffer, MAX_BUFFER_SIZE, &responseType);
    
    if (responseType == DATA_TYPE_ACK) {
        logInfo("Data delete successful");
        return 0;
    }
    
    logError("Data delete failed");
    return -1;
}

// 申请抽查数据
int dataSampleRequest(ClientContext *context, const char *batch, const char *startDate, const char *endDate) {
    cJSON *root = cJSON_CreateObject();
    if (batch && strlen(batch) > 0) {
        cJSON_AddStringToObject(root, "batch", batch);
    }
    if (startDate && strlen(startDate) > 0) {
        cJSON_AddStringToObject(root, "startDate", startDate);
    }
    if (endDate && strlen(endDate) > 0) {
        cJSON_AddStringToObject(root, "endDate", endDate);
    }
    cJSON_AddStringToObject(root, "username", context->user.username);
    cJSON_AddStringToObject(root, "role", context->user.role);
    
    char *jsonStr = cJSON_PrintUnformatted(root);
    int ret = sendPacket(context->sockfd, DATA_TYPE_DATA_SAMPLE, jsonStr);
    
    cJSON_free(jsonStr);
    cJSON_Delete(root);
    
    if (ret < 0) {
        logError("Failed to send sample request");
        return -1;
    }
    
    // 等待响应
    char responseBuffer[MAX_BUFFER_SIZE];
    unsigned char responseType;
    waitForResponse(responseBuffer, MAX_BUFFER_SIZE, &responseType);
    
    // 保存数据到本地
    if (responseType != DATA_TYPE_ERROR) {
        char filename[100];
        time_t now = time(NULL);
        struct tm *tm_now = localtime(&now);
        sprintf(filename, "%s/sample_%s_%04d%02d%02d_%02d%02d%02d.txt", 
                LOCAL_DATA_DIR, context->user.username, 
                tm_now->tm_year + 1900, tm_now->tm_mon + 1, tm_now->tm_mday,
                tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec);
        
        FILE *fp = fopen(filename, "w");
        if (fp) {
            fprintf(fp, "%s", responseBuffer);
            fclose(fp);
            printf("Sample data saved to: %s\n", filename);
        } else {
            printf("Failed to save sample data\n");
        }
    }
    
    return 0;
}

// 上传错误数据编号
int reportErrorData(ClientContext *context, const char *waferId) {
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "waferId", waferId);
    cJSON_AddStringToObject(root, "username", context->user.username);
    cJSON_AddStringToObject(root, "role", context->user.role);
    cJSON_AddNumberToObject(root, "reportTime", time(NULL));
    
    char *jsonStr = cJSON_PrintUnformatted(root);
    int ret = sendPacket(context->sockfd, DATA_TYPE_DATA_ERROR_REPORT, jsonStr);
    
    cJSON_free(jsonStr);
    cJSON_Delete(root);
    
    if (ret < 0) {
        logError("Failed to send error data report");
        return -1;
    }
    
    // 等待响应
    char responseBuffer[MAX_BUFFER_SIZE];
    unsigned char responseType;
    waitForResponse(responseBuffer, MAX_BUFFER_SIZE, &responseType);
    
    if (responseType == DATA_TYPE_ACK) {
        logInfo("Error data reported successfully");
        return 0;
    }
    
    logError("Error data report failed");
    return -1;
}

// 查询本地数据文件
void queryLocalData() {
    DIR *dir;
    struct dirent *entry;
    
    printf("\n--- Local Data Files ---");
    
    dir = opendir(LOCAL_DATA_DIR);
    if (!dir) {
        printf("\nNo local data directory found, creating...\n");
        mkdir(LOCAL_DATA_DIR, 0755);
        return;
    }
    
    int count = 0;
    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_REG && strstr(entry->d_name, ".txt")) {
            printf("\n%s", entry->d_name);
            count++;
        }
    }
    
    if (count == 0) {
        printf("\nNo local data files found\n");
    }
    
    closedir(dir);
    printf("\n------------------------\n");
}



// 主函数
int main() {
    ClientContext context;
    pthread_t receiveThread;
    int choice;
    
    // 初始化本地数据目录
    mkdir(LOCAL_DATA_DIR, 0755);
    
    // 初始化日志
    logInit("client.log", LOG_LEVEL_INFO, 1);
    logInfo("Starting client...");
    
    // 连接服务器
    context.sockfd = connectTCPServer(SERVER_IP, SERVER_PORT);
    if (context.sockfd < 0) {
        logFatal("Failed to connect to server %s:%d", SERVER_IP, SERVER_PORT);
    }
    
    logInfo("Connected to server %s:%d", SERVER_IP, SERVER_PORT);
    
    // 初始化心跳
    context.heartbeat = heartbeatInit(HEARTBEAT_INTERVAL, HEARTBEAT_TIMEOUT, 
                                     clientSendHeartbeat, &context);
    if (!context.heartbeat) {
        logError("Failed to initialize heartbeat");
    } else {
        heartbeatStart(context.heartbeat);
        logInfo("Heartbeat started with interval %d seconds", HEARTBEAT_INTERVAL);
    }
    
    // 设置运行标志
    context.running = 1;
    context.loggedIn = 0;
    
    // 启动接收线程
    pthread_create(&receiveThread, NULL, receiveResponse, &context);
    
    // 登录循环
    while (context.running) {
        if (!context.loggedIn) {
            showLoginMenu();
            scanf("%d", &choice);
            getchar(); // 清空输入缓冲区
            
            switch (choice) {
                case 1: {
                    char username[50], password[50];
                    printf("请输入用户名: ");
                    fgets(username, sizeof(username), stdin);
                    username[strcspn(username, "\n")] = 0;
                    
                    printf("请输入密码: ");
                    fgets(password, sizeof(password), stdin);
                    password[strcspn(password, "\n")] = 0;
                    
                    if (userLogin(&context, username, password) == 0) {
                        printf("登录成功！\n");
                    } else {
                        printf("登录失败，请重试！\n");
                    }
                    break;
                }
                case 2: {
                    char username[50], password[50], confirmPassword[50];
                    printf("请输入用户名: ");
                    fgets(username, sizeof(username), stdin);
                    username[strcspn(username, "\n")] = 0;
                    
                    printf("请输入密码: ");
                    fgets(password, sizeof(password), stdin);
                    password[strcspn(password, "\n")] = 0;
                    
                    printf("请确认密码: ");
                    fgets(confirmPassword, sizeof(confirmPassword), stdin);
                    confirmPassword[strcspn(confirmPassword, "\n")] = 0;
                    
                    if (strcmp(password, confirmPassword) != 0) {
                        printf("两次输入的密码不一致！\n");
                        break;
                    }
                    
                    if (userRegister(&context, username, password, "maintenance_engineer") == 0) {
                        printf("注册成功！\n");
                    } else {
                        printf("注册失败，请重试！\n");
                    }
                    break;
                }
                case 0:
                    context.running = 0;
                    break;
                default:
                    printf("无效的选择，请重试！\n");
            }
        } else {
            // 主菜单循环
            while (context.loggedIn && context.running) {
                showMainMenu(context.user.role);
                scanf("%d", &choice);
                getchar(); // 清空输入缓冲区
                
                int base = (strcmp(context.user.role, "maintenance_engineer") == 0) ? 0 : -3;
                
                switch (choice) {
                    case 1: {
                        // 修改密码
                        char oldPassword[50], newPassword[50], confirmPassword[50];
                        printf("请输入旧密码: ");
                        fgets(oldPassword, sizeof(oldPassword), stdin);
                        oldPassword[strcspn(oldPassword, "\n")] = 0;
                        
                        printf("请输入新密码: ");
                        fgets(newPassword, sizeof(newPassword), stdin);
                        newPassword[strcspn(newPassword, "\n")] = 0;
                        
                        printf("请确认新密码: ");
                        fgets(confirmPassword, sizeof(confirmPassword), stdin);
                        confirmPassword[strcspn(confirmPassword, "\n")] = 0;
                        
                        if (strcmp(newPassword, confirmPassword) != 0) {
                            printf("两次输入的新密码不一致！\n");
                        } else if (userChangePassword(&context, oldPassword, newPassword) == 0) {
                            printf("密码修改成功！\n");
                        } else {
                            printf("密码修改失败，请重试！\n");
                        }
                        break;
                    }
                    case 2 + base: {
                        // 维护工程师注册新用户，生产工程师查询检测记录
                        if (strcmp(context.user.role, "maintenance_engineer") == 0) {
                            char username[50], password[50], confirmPassword[50], role[20];
                            printf("请输入用户名: ");
                            fgets(username, sizeof(username), stdin);
                            username[strcspn(username, "\n")] = 0;
                            
                            printf("请输入密码: ");
                            fgets(password, sizeof(password), stdin);
                            password[strcspn(password, "\n")] = 0;
                            
                            printf("请确认密码: ");
                            fgets(confirmPassword, sizeof(confirmPassword), stdin);
                            confirmPassword[strcspn(confirmPassword, "\n")] = 0;
                            
                            printf("请选择角色(production_engineer/maintenance_engineer): ");
                            fgets(role, sizeof(role), stdin);
                            role[strcspn(role, "\n")] = 0;
                            
                            if (strcmp(password, confirmPassword) != 0) {
                                printf("两次输入的密码不一致！\n");
                            } else if (userRegister(&context, username, password, role) == 0) {
                                printf("用户注册成功！\n");
                            } else {
                                printf("用户注册失败，请重试！\n");
                            }
                        } else {
                            char batch[50], startDate[20], endDate[20], defectType[30];
                            printf("请输入批次号(可选，直接回车跳过): ");
                            fgets(batch, sizeof(batch), stdin);
                            batch[strcspn(batch, "\n")] = 0;
                            
                            printf("请输入开始日期(可选，格式: YYYY-MM-DD): ");
                            fgets(startDate, sizeof(startDate), stdin);
                            startDate[strcspn(startDate, "\n")] = 0;
                            
                            printf("请输入结束日期(可选，格式: YYYY-MM-DD): ");
                            fgets(endDate, sizeof(endDate), stdin);
                            endDate[strcspn(endDate, "\n")] = 0;
                            
                            printf("请输入缺陷类型(可选): ");
                            fgets(defectType, sizeof(defectType), stdin);
                            defectType[strcspn(defectType, "\n")] = 0;
                            
                            dataQuery(&context, batch, startDate, endDate, defectType);
                        }
                        break;
                    }
                    case 3 + base: {
                        // 维护工程师删除用户，生产工程师删除检测记录
                        if (strcmp(context.user.role, "maintenance_engineer") == 0) {
                            char username[50];
                            printf("请输入要删除的用户名: ");
                            fgets(username, sizeof(username), stdin);
                            username[strcspn(username, "\n")] = 0;
                            
                            char confirm[10];
                            printf("确定要删除用户 %s 吗？(yes/no): ", username);
                            fgets(confirm, sizeof(confirm), stdin);
                            confirm[strcspn(confirm, "\n")] = 0;
                            
                            if (strcmp(confirm, "yes") == 0 || strcmp(confirm, "YES") == 0) {
                                if (userDelete(&context, username) == 0) {
                                    printf("用户删除成功！\n");
                                } else {
                                    printf("用户删除失败！\n");
                                }
                            }
                        } else {
                            char batch[50], startDate[20], endDate[20];
                            printf("请输入批次号(可选，直接回车跳过): ");
                            fgets(batch, sizeof(batch), stdin);
                            batch[strcspn(batch, "\n")] = 0;
                            
                            printf("请输入开始日期(可选，格式: YYYY-MM-DD): ");
                            fgets(startDate, sizeof(startDate), stdin);
                            startDate[strcspn(startDate, "\n")] = 0;
                            
                            printf("请输入结束日期(可选，格式: YYYY-MM-DD): ");
                            fgets(endDate, sizeof(endDate), stdin);
                            endDate[strcspn(endDate, "\n")] = 0;
                            
                            char confirm[10];
                            printf("确定要删除满足条件的记录吗？(yes/no): ");
                            fgets(confirm, sizeof(confirm), stdin);
                            confirm[strcspn(confirm, "\n")] = 0;
                            
                            if (strcmp(confirm, "yes") == 0 || strcmp(confirm, "YES") == 0) {
                                if (dataDelete(&context, batch, startDate, endDate) == 0) {
                                    printf("数据删除成功！\n");
                                } else {
                                    printf("数据删除失败！\n");
                                }
                            }
                        }
                        break;
                    }
                    case 4 + base: {
                        // 维护工程师查看所有用户，生产工程师申请抽查数据
                        if (strcmp(context.user.role, "maintenance_engineer") == 0) {
                            userQuery(&context, NULL);
                        } else {
                            char batch[50], startDate[20], endDate[20];
                            printf("请输入批次号(可选，直接回车跳过): ");
                            fgets(batch, sizeof(batch), stdin);
                            batch[strcspn(batch, "\n")] = 0;
                            
                            printf("请输入开始日期(可选，格式: YYYY-MM-DD): ");
                            fgets(startDate, sizeof(startDate), stdin);
                            startDate[strcspn(startDate, "\n")] = 0;
                            
                            printf("请输入结束日期(可选，格式: YYYY-MM-DD): ");
                            fgets(endDate, sizeof(endDate), stdin);
                            endDate[strcspn(endDate, "\n")] = 0;
                            
                            dataSampleRequest(&context, batch, startDate, endDate);
                        }
                        break;
                    }
                    case 5 + base: {
                        // 上传错误数据编号
                        char waferId[50];
                        printf("请输入错误电池片编号: ");
                        fgets(waferId, sizeof(waferId), stdin);
                        waferId[strcspn(waferId, "\n")] = 0;
                        
                        if (reportErrorData(&context, waferId) == 0) {
                            printf("错误数据编号上传成功！\n");
                        } else {
                            printf("错误数据编号上传失败！\n");
                        }
                        break;
                    }
                    case 6 + base: {
                        // 查询本地数据文件
                        queryLocalData();
                        break;
                    }
                    case 0:
                        context.loggedIn = 0;
                        printf("已退出登录！\n");
                        break;
                    default:
                        printf("无效的选择，请重试！\n");
                }
            }
        }
    }
    
    // 清理资源
    logInfo("Stopping client...");
    context.running = 0;
    
    if (context.heartbeat) {
        heartbeatStop(context.heartbeat);
        heartbeatDestroy(context.heartbeat);
    }
    
    pthread_join(receiveThread, NULL);
    close(context.sockfd);
    logCleanup();
    
    logInfo("Client stopped");
    return 0;
}